#ifndef TC_RANDOMMT_HH
#define TC_RANDOMMT_HH

/** \file RandomMT.hh
 *
 * Mersenne Twister random number generator -- a C++ class MTRand
 * Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus
 * Richard J. Wagner  v1.1  28 September 2009  wagnerr@umich.edu
 * The Mersenne Twister is an algorithm for generating random numbers.  It
 * was designed with consideration of the flaws in various other generators.
 * The period, 2^19937-1, and the order of equidistribution, 623 dimensions,
 * are far greater.  The generator is also fast; it avoids multiplication and
 * division, and it benefits from caches and pipelines.  For more information
 * see the inventors' web page at
 * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
 *
 * Reference
 * M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-Dimensionally
 * Equidistributed Uniform Pseudo-Random Number Generator", ACM Transactions on
 * Modeling and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3-30.
 * 
 * (c) Copyright  Semih Cemiloglu
 * All rights reserved, see COPYRIGHT file for details.
 *
 * Based on Richard J. Wagner's MersenneTwister.h package v1.1
 *
 */

#include <time.h>
#include <iosfwd>

#if !defined(uint32_t)
 #if defined(_MSC_VER) 
   /* MS Visual C++ */
   #include <VCpp_stdint.h>
 #else
   #include <stdint.h>   /* C99 standard integers */
   // For unknown compilers, you can use portable stdint.h
   //include <Port_stdint.h> 
 #endif
#endif

#include "Global.hh"



namespace TC {

class RandomMT {

  // FRIENDS
  friend std::ostream& operator<<( std::ostream&, const RandomMT&);
  friend std::istream& operator>>( std::istream&, RandomMT&);
  
  
  // DATA
public:
  enum { N = 624 };       // length of state vector
  enum { SAVE = N + 1 };  // length of array for save()

protected:
  enum { M = 397 };      // period parameter
  uint32_t m_state[N];   // internal state
  uint32_t *m_next;      // next value to get from state
  int m_left;            // number of values left before reload needed

  // METHODS 
public:
  // initialize with a simple uint32_t
  RandomMT(const uint32_t oneSeed);
  // or array
  RandomMT(uint32_t *const bigSeed, uint32_t const seedLength = N );
  // auto-initialize with time() and clock()
  RandomMT();
  // copy
  RandomMT(const RandomMT& o);  
  RandomMT& operator=(const RandomMT& o);

  
  // Do NOT use for CRYPTOGRAPHY without securely hashing several returned
  // values together, otherwise the generator state can be learned after
  // reading 624 consecutive values.
  
  // Access to 32-bit random numbers
  uint32_t randInt();                   // integer in [0,2^32-1]
  uint32_t randInt( const uint32_t n ); // integer in [0,n] for n < 2^32
  double rand();                        // real number in [0,1]
  double rand( const double n );        // real number in [0,n]
  double randExc();                     // real number in [0,1)
  double randExc( const double n );     // real number in [0,n)
  double randDblExc();                  // real number in (0,1)
  double randDblExc( const double n );  // real number in (0,n)
  double operator()();                  // same as rand()
  
  // Access to 53-bit random numbers (capacity of IEEE double precision)
  double rand53();  // real number in [0,1)
  
  // Access to nonuniform random number distributions
  double randNorm(const double mean = 0.0, const double stddev = 1.0);
  
  // Re-seeding functions with same behavior as initializers
  void seed(const uint32_t oneSeed);
  void seed(uint32_t *const bigSeed, const uint32_t seedLength = N);
  void seed();
  
  // Saving and loading generator state
  void save(uint32_t* saveArray) const;  // to array of size SAVE
  void load(uint32_t *const loadArray);  // from such array


protected:
  void initialize(const uint32_t oneSeed);
  void reload();

  uint32_t hiBit(const uint32_t u) const
  { return u & 0x80000000UL; }
  uint32_t loBit(const uint32_t u) const
  { return u & 0x00000001UL; }
  uint32_t loBits(const uint32_t u) const
  { return u & 0x7fffffffUL; }
  uint32_t mixBits( const uint32_t u, const uint32_t v) const
  { return hiBit(u) | loBits(v); }
  uint32_t magic(const uint32_t u) const
  { return loBit(u) ? 0x9908b0dfUL : 0x0UL; }
  uint32_t twist(const uint32_t m, const uint32_t s0, const uint32_t s1) const
  { return m ^ (mixBits(s0,s1)>>1) ^ magic(s1); }

  // STATIC FUNCTIONS
  static uint32_t Hash(time_t t, clock_t c);
};

} // end namespace


// Include inline function definitions
#ifdef TC_USE_INLINE
# include "RandomMT.inl"
#endif


#endif  /* Include guard */

